#include "helper.h"
#include "monitor.h"
#include "reg.h"

extern uint32_t instr;
extern char assembly[80];

/* decode I16-type instrucion with signed immediate */
static void decode_i16_type(uint32_t instr) {

	op_src1->type = OP_TYPE_REG;
	op_src1->reg = (instr >> 5) & 0x0000001F;
	op_src1->val = reg_w(op_src1->reg); // 源寄存器src1

	op_src2->type = OP_TYPE_IMM;
	op_src2->imm = (instr >> 10) & 0x0000FFFF;
	op_src2->val = op_src2->imm; //立即数是src2,offs16

	op_dest->type = OP_TYPE_REG;
	op_dest->reg = instr & 0x0000001F;//后5位是目标寄存器
    op_dest->val = reg_w(op_dest->reg); 
}
//TODO:添加指令beq bne
make_helper(beq) {

	decode_i16_type(instr);
	if(op_src1->val == op_dest->val)
    {
        uint32_t temp;
        if(op_src2->val >> 15)//符号扩展1
            temp = (op_src2->val << 2) + 0xFFFC0000;
        else//符号扩展0
            temp = op_src2->val << 2; 
        pc = pc + temp;
    }
	sprintf(assembly, "beq\t%s,\t%s,\t0x%08x", REG_NAME(op_src1->reg), REG_NAME(op_dest->reg), op_src2->imm);
}
make_helper(bne)
{
    decode_i16_type(instr);
    if(op_src1->val != op_dest->val)
    {
        uint32_t temp;
        if(op_src2->val >> 15)//符号扩展1
            temp = (op_src2->val << 2) + 0xFFFC0000;
        else//符号扩展0
            temp = op_src2->val << 2; 
        pc += temp;
    }
	sprintf(assembly, "bne\t%s,\t%s,\t0x%08x", REG_NAME(op_src1->reg), REG_NAME(op_dest->reg), op_src2->imm);
}

make_helper(bge) {

    decode_i16_type(instr);
    if (op_src1->val >= op_dest->val)
    {
        uint32_t temp;
        if (op_src2->val >> 15)//符号扩展1
            temp = (op_src2->val << 2) + 0xFFFC0000;
        else//符号扩展0
            temp = op_src2->val << 2;
        pc += temp;
    }
    sprintf(assembly, "bge\t%s,\t%s,\t0x%08x", REG_NAME(op_src1->reg), REG_NAME(op_dest->reg), op_src2->imm);

}

make_helper(blt){

    decode_i16_type(instr);
    // 比较两个源寄存器的值
    if(op_src1->val < op_dest->val) // 如果 op_src1 小于 op_dest
    {
        uint32_t temp;

        if(op_src2->val >> 15) // 符号扩展1
            temp = (op_src2->val << 2) + 0xFFFC0000; // 符号扩展为负数
        else // 符号扩展0
            temp = op_src2->val << 2; // 直接左移2位
        pc += temp; // 更新程序计数器
    }
    sprintf(assembly, "blt\t%s,\t%s,\t0x%08x", REG_NAME(op_src1->reg), REG_NAME(op_dest->reg), op_src2->imm);
}